(in-ns 'com.dubious.clojure)

; calculate the number of digits of a number
(defn number-digits [value]
  ; I've had several attempts at creating this method but keep running out of memory
  
  ; This attempts to use division by 10 and recursion but runs out of memory around 600
  ; (if (> (bigint (/ value 10)) 0)
  ;  (number-digits (bigint (/ value 10)) (+ currentDigits 1))
  ;  (+ currentDigits 1)) 
  
  ; This attempts to convert to string and count the number of chars.  It does a bit better but still runs out of memory.
  (count (str value))
  
  ; let's try a similar / 10 approach but use recur keyword to save on memory
  ; it did not seem to work.  and it is slower, anyway
  ;(loop [
  ;       working-value value, 
  ;       currentDigits 0]
  ;  (if (= (bigint (/ working-value 10)) 0)
  ;    (+ currentDigits 1)
  ;    (recur (bigint (/ working-value 10)) (+ currentDigits 1))
  ;  ) 
  ;)
)

; calculate fibonacci using recursion and check whether it has the proper number of digits at each 
; step
; this implementation does not scale to 1000, due to usage of too much memory
(defn calculate-fibonacci [n_2, n_1, numDigits, term]
  (let [
        ; calculate the nth value in the fibonacci sequence
        n (bigint (+ n_2 n_1)), 
        ; determine the number of digits in the nth value
        n-size (number-digits n)]
    (if (>= n-size numDigits)
      ; value with proper number of digits found
      (+ 1 term)
      ; still don't have enough digits, examine next value in sequence
      ; note: unbounded recursion is discouraged. should use the recur keyword instead
      ;       i will do this in version 2
      (calculate-fibonacci n_1, n, numDigits, (+ 1 term))
    )
  )
)
  
(defn problem-25 [numDigits]
  (let [fib (calculate-fibonacci (bigint 1) (bigint 1), numDigits, 2)]
    (println "first fibonacci term with " numDigits " digits: " fib)
  )
)

;
;
;
;

; calculate fibonacci using recursion and check whether it has the proper number of digits at each 
; step
; this implementation uses the recur special form to save on memory
(defn calculate-fibonacci-2 [num-digits]
  (loop [
        term 2,
        n_2 (bigint 1),
        n_1 (bigint 1)]
    (let [
        ; calculate the nth value in the fibonacci sequence
        n (bigint (+ n_2 n_1)), 
        ; determine the number of digits in the nth value
        n-size (number-digits n)]
      (if (>= n-size num-digits)
        ; value with proper number of digits found
        (+ 1 term)
        ; still don't have enough digits, examine next value in sequence
        (recur (+ 1 term) n_1 n)
      )
    )
  )
)
  
(defn problem-25-2 [num-digits]
  (let [fib (calculate-fibonacci-2 num-digits)]
    (println "first fibonacci term with " num-digits " digits: " fib)
  )
)
  
; example of use of recurse:
; note that the call to recurse is working on the loop and that the
; values n and 1 are assigned, initially, but ignored in subsequent
; recursion steps
;(def factorial
;  (fn [n]
;    (loop [cnt n acc 1]
;       (if (zero? cnt)
;            acc
;          (recur (dec cnt) (* acc cnt))))))

; TODO:
; [ ] test the code
; [ ] organize the source using approved standards
; [ ] build and run tests using maven